﻿using System;
using System.IO;
using System.Text.RegularExpressions;
using TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Fundamental;

namespace TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Functions.Readers
{
    /// <summary>
    /// Reads BooleanFunction from simple text plain format: x1y1z1 f1\nx2y2z2 f2.
    /// </summary>
    public class BooleanFunctionReaderPlain : BooleanFunctionReader
    {
        // Properties

        /// <summary>
        /// Input string to read from.
        /// </summary>
        public string Input { get; set; }


        // Methods

        /// <summary>
        /// Reads BooleanFunction object from text plain format.
        /// </summary>
        public override void Read()
        {
            if (ReferenceEquals(null, Function))
            {
                throw new InvalidOperationException("BooleanFunction object required to read data to.");
            }

            if (Input == string.Empty)
            {
                throw new InvalidOperationException("Input string required.");
            }

            // splitting to lines
            var delimeters = new[] { "\n", "\r\n" };
            var lines = Input.Split(delimeters, Int32.MaxValue, StringSplitOptions.RemoveEmptyEntries);
            if (lines.Length == 0)
            {
                throw new InvalidDataException("Invalid source string: no one line of values.");
            }

            // parsing lines by pattern
            var pattern = new Regex("([01-]+)\\s+([01])");
            var domain0 = new CubeSet();
            var domain1 = new CubeSet();
            var dimension = 0;
            foreach (var line in lines)
            {
                if (line == String.Empty) continue;
                
                var match = pattern.Match(line);
                if (!match.Success)
                {
                    throw new InvalidDataException("Invalid format for source string.");
                }

                var vector = match.Groups[1].ToString();
                var funcValue = match.Groups[2].ToString();

                if (dimension == 0)
                {
                    dimension = vector.Length;
                }

                if (vector.Length != dimension)
                {
                    throw new InvalidDataException("Invalid format for source string: different cubes dimensions for one function.");
                }

                // building cube
                Cube cube;
                try
                {
                    cube = new Cube(vector);    
                }
                catch(ArgumentException e)
                {
                    throw new InvalidDataException("Invalid format for source string: invalid ternary vector character", e);
                }
                
                if (funcValue == "1")
                {
                    domain1.Add(cube);
                }
                else
                {
                    domain0.Add(cube);
                }
            }

            // determining function
            Function.Domain0 = domain0;
            Function.Domain1 = domain1;
        }
    }
}
